package com.balloon.springboot.datasource.conf;

import com.balloon.springboot.datasource.datasourceholder.DataSourceContextHolder;
import com.balloon.springboot.datasource.entity.DataSourcePropertiesBean;
import com.balloon.springboot.datasource.prorperties.DefaultDataSource;
import com.balloon.springboot.datasource.prorperties.LocalDataSourceProperties;
import com.balloon.springboot.datasource.prorperties.SecondDataSource;
import com.balloon.springboot.datasource.prorperties.ThirdDataSource;
import com.zaxxer.hikari.HikariDataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Component;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 数据源初初始化注册器
 *
 * @author liaofuxing
 * @data 2021/9/18
 */
@Component
public class DataSourceConfigRegister {

    private static final Logger log = LoggerFactory.getLogger(DataSourceConfigRegister.class);

    public LocalDataSourceProperties localDataSourceProperties;


    /**
     * 数据源构造器
     *
     * @param localDataSourceProperties 本地配置文件
     */
    public DataSourceConfigRegister(LocalDataSourceProperties localDataSourceProperties) {
        this.localDataSourceProperties = localDataSourceProperties;
    }

    /**
     * 初始化数据源路由和数据源配置文件
     *
     * @return List<DataSourcePropertiesBean> 数据源配置文件集合
     */
    public List<DataSourcePropertiesBean> initDataSourceProperties(HikariDataSource defaultHikariDataSource) throws SQLException {

        Map<String, Object> supportDataSourceRouteKeyAndPropertiesBeansMap = getSupportDataSourceRouteKeyAndPropertiesBeans(defaultHikariDataSource);
        String[] supportDataSourceRouteKeys = (String[]) supportDataSourceRouteKeyAndPropertiesBeansMap.get("routeKey");
        for (String supportDataSourceRouteKey : supportDataSourceRouteKeys) {
            DataSourceContextHolder.addDataSource(supportDataSourceRouteKey);
        }
        return (List<DataSourcePropertiesBean>) supportDataSourceRouteKeyAndPropertiesBeansMap.get("supportDataSourcePropertiesList");
    }

    /**
     * 组装数据源路由
     *
     * @return Map<String, Object>  数据源路由数组和数据源配置集合
     */
    public Map<String, Object> getSupportDataSourceRouteKeyAndPropertiesBeans(HikariDataSource defaultHikariDataSource) throws SQLException {
        List<DataSourcePropertiesBean> supportDataSourcePropertiesList = getSupportDataSourcePropertiesList(defaultHikariDataSource);
        String[] supportDataSourceRouteKey = new String[supportDataSourcePropertiesList.size()];
        for (int x = 0; x <= supportDataSourcePropertiesList.size() - 1; x++) {
            supportDataSourceRouteKey[x] = supportDataSourcePropertiesList.get(x).getType();
        }
        Map<String, Object> map = new HashMap<>();
        map.put("routeKey", supportDataSourceRouteKey);
        map.put("supportDataSourcePropertiesList", supportDataSourcePropertiesList);
        return map;
    }

    /**
     * 尝试从默认的数据源数据库中加载数据源配置
     *
     * @param defaultHikariDataSource 默认数据源
     * @return List<DataSourcePropertiesBean> 数据源配置
     */
    public List<DataSourcePropertiesBean> getSupportDataSourcePropertiesList(HikariDataSource defaultHikariDataSource) throws SQLException {
        List<DataSourcePropertiesBean> dataSourcePropertiesBeanList = new ArrayList<>();
        // 将默认的数据源添加到初始化配置集合
        DataSourcePropertiesBean defaultDataSourcePropertiesBean = new DataSourcePropertiesBean();
        DefaultDataSource defaultDataSource = localDataSourceProperties.getDefaultDataSource();
        BeanUtils.copyProperties(defaultDataSource, defaultDataSourcePropertiesBean);
        dataSourcePropertiesBeanList.add(defaultDataSourcePropertiesBean);

        if (localDataSourceProperties.getConf().getInitializeDatasourceByDb()) {
            log.info("从数据库读取数据源已开启");
            String sql = "select id,driver_class_name,url,username,password,type from tab_data_source";
            try (Connection connection = defaultHikariDataSource.getConnection(); PreparedStatement ps = connection.prepareStatement(sql); ResultSet rs = ps.executeQuery();) {
                while (rs.next()) {
                    //遍历查询结果，每循环一次就代表一行数据
                    DataSourcePropertiesBean dataSourcePropertiesBean = new DataSourcePropertiesBean();
                    dataSourcePropertiesBean.setUrl(rs.getString("url"));
                    dataSourcePropertiesBean.setDriverClassName(rs.getString("driver_class_name"));
                    dataSourcePropertiesBean.setUsername(rs.getString("username"));
                    dataSourcePropertiesBean.setPassword(rs.getString("password"));
                    dataSourcePropertiesBean.setType(rs.getString("type"));
                    dataSourcePropertiesBeanList.add(dataSourcePropertiesBean);
                }

            } catch (SQLException e) {
                log.error("数据库中没有找到数据源配置表,若不需要从数据库加载数据源,请在配置文件db.conf.initialize-datasource-by-db中关闭");
                e.printStackTrace();
            }
        } else {
            log.info("从数据库读取数据源已关闭,将从配置文件中读取数据源");
            if (localDataSourceProperties.getSecondDataSource() != null) {
                DataSourcePropertiesBean secondDataSourcePropertiesBean = new DataSourcePropertiesBean();
                SecondDataSource secondDataSource = localDataSourceProperties.getSecondDataSource();
                BeanUtils.copyProperties(secondDataSource, secondDataSourcePropertiesBean);
                dataSourcePropertiesBeanList.add(secondDataSourcePropertiesBean);
            }

            if (localDataSourceProperties.getThirdDataSource() != null) {
                DataSourcePropertiesBean thirdDataSourcePropertiesBean = new DataSourcePropertiesBean();
                ThirdDataSource thirdDataSource = localDataSourceProperties.getThirdDataSource();
                BeanUtils.copyProperties(thirdDataSource, thirdDataSourcePropertiesBean);
                dataSourcePropertiesBeanList.add(thirdDataSourcePropertiesBean);
            }
        }

        return dataSourcePropertiesBeanList;
    }

}